VM தொகுப்பு அறிமுகம்
VM (மெய்நிகர் இயந்திரம்) தொகுதி தனிமைப்படுத்தப்பட்ட சூழல்களுக்குள் குறியீட்டை தொகுத்து இயக்க உங்களை அனுமதிக்கிறது.
இது பின்வருவனவற்றிற்கு பயனுள்ளதாக இருக்கிறது:
நம்பப்படாத குறியீட்டை பாதுகாப்பாக இயக்குதல்
சாண்ட்பாக்ஸில் நம்பப்படாத குறியீட்டை பாதுகாப்பாக இயக்குதல்
JavaScript குறியீட்டை டைனமிக்காக மதிப்பீடு செய்தல்
JavaScript குறியீட்டை டைனமிக்காக மதிப்பீடு செய்தல்
பிளகின்கள் மற்றும் நீட்டிப்பு அமைப்புகளை உருவாக்குதல்
பிளகின்கள் மற்றும் நீட்டிப்பு அமைப்புகளை உருவாக்குதல்
தனிப்பயன் ஸ்கிரிப்டிங் சூழல்களை கட்டமைத்தல்
தனிப்பயன் ஸ்கிரிப்டிங் சூழல்களை கட்டமைத்தல்
தனிமைப்பாட்டில் குறியீட்டை சோதித்தல்
தனிமைப்பாட்டில் குறியீட்டை சோதித்தல்
எச்சரிக்கை:
VM தொகுதி முக்கிய JavaScript சூழலில் இருந்து தனிமைப்பாட்டை வழங்கினாலும், இது முழுமையான பாதுகாப்பான சாண்ட்பாக்ஸ் அல்ல. நம்பப்படாத குறியீட்டை இயக்குவதற்கான ஒரே பாதுகாப்பு பொறிமுறையாக இது பயன்படுத்தப்படக்கூடாது.
VM தொகுப்பை இறக்குமதி செய்தல்
VM தொகுப்பைப் பயன்படுத்த, உங்கள் Node.js பயன்பாட்டில் அதை தேவைப்படுத்த வேண்டும்:
const vm = require('vm');
முக்கிய கருத்துகள்
VM தொகுதியில் பல முக்கிய கூறுகள் உள்ளன:
| கூறு | விளக்கம் |
|---|---|
| Script | வெவ்வேறு சூழல்களில் பல முறை இயக்கப்படக்கூடிய தொகுக்கப்பட்ட JavaScript குறியீடு |
| Context | ஸ்கிரிப்ட்கள் இயக்கும் தனிமைப்படுத்தப்பட்ட உலகளாவிய பொருள், சாண்ட்பாக்ஸ்டு சூழலுக்கு ஒத்தது |
| ContextifiedObject | ஒரு VM சூழலுடன் தொடர்புபடுத்தப்பட்ட மற்றும் அதன் உலகளாவிய பொருளாக செயல்படும் ஒரு பொருள் |
அடிப்படை பயன்பாடு: ஒரு சூழலில் JavaScript ஐ இயக்குதல்
VM தொகுப்பைப் பயன்படுத்துவதற்கான எளிய வழி ஒரு சூழலில் குறியீட்டை இயக்குவதாகும்:
const vm = require('vm');
// Create a context object
const context = { x: 2 };
// Compile and run a script in the context
vm.createContext(context);
vm.runInContext('x = x * 2; y = 10;', context);
// Inspect the modified context
console.log(context); // Outputs: { x: 4, y: 10 }
இந்த எடுத்துக்காட்டில்:
VM தொகுப்பு முறைகள்
ஸ்கிரிப்ட் முறைகள்
| முறை | விளக்கம் |
|---|---|
| vm.Script(code[, options]) | தொகுக்கப்பட்ட குறியீட்டை பிரதிநிதித்துவப்படுத்தும் ஒரு புதிய Script பொருளை உருவாக்குகிறது |
| script.runInContext(contextObject[, options]) | குறிப்பிட்ட சூழலில் தொகுக்கப்பட்ட குறியீட்டை இயக்குகிறது |
| script.runInNewContext([contextObject][, options]) | ஒரு புதிய சூழலில் தொகுக்கப்பட்ட குறியீட்டை இயக்குகிறது |
| script.runInThisContext([options]) | தற்போதைய சூழலில் தொகுக்கப்பட்ட குறியீட்டை இயக்குகிறது |
சூழல் முறைகள்
| முறை | விளக்கம் |
|---|---|
| vm.createContext([contextObject][, options]) | ஸ்கிரிப்ட் இயக்கத்திற்குப் பயன்படுத்தக்கூடிய ஒரு புதிய சூழலை உருவாக்குகிறது |
| vm.isContext(object) | ஒரு பொருள் சூழலாக்கப்பட்டுள்ளதா என சரிபார்க்கிறது |
| vm.runInContext(code, contextObject[, options]) | கொடுக்கப்பட்ட சூழலில் குறியீட்டை தொகுத்து இயக்குகிறது |
| vm.runInNewContext(code[, contextObject][, options]) | ஒரு புதிய சூழலில் குறியீட்டை தொகுத்து இயக்குகிறது |
| vm.runInThisContext(code[, options]) | தற்போதைய சூழலில் குறியீட்டை தொகுத்து இயக்குகிறது |
ஸ்கிரிப்ட்களை உருவாக்குதல் மற்றும் தொகுத்தல்
அதே குறியீட்டை பல முறை இயக்க வேண்டியிருக்கும் போது சிறந்த செயல்திறனுக்கு, Script வகுப்பைப் பயன்படுத்தி அதை முன்கூட்டியே தொகுக்கலாம்:
const vm = require('vm');
// Compile the script once
const script = new vm.Script('x += 40; let z = 30;');
// Create multiple contexts
const context1 = { x: 10 };
const context2 = { x: 20 };
// Contextify the objects
vm.createContext(context1);
vm.createContext(context2);
// Run the same script in different contexts
script.runInContext(context1);
script.runInContext(context2);
console.log(context1); // Outputs: { x: 50, z: 30 }
console.log(context2); // Outputs: { x: 60, z: 30 }
குறிப்பு:
ஸ்கிரிப்ட்களை தனித்தனியாக தொகுப்பது நீங்கள் அதே குறியீட்டை பல முறை இயக்க வேண்டியிருக்கும் போது மிகவும் திறமையானது, ஏனெனில் பாகுபடுத்துதல் மற்றும் தொகுப்பு படிகள் ஒருமுறை மட்டுமே நடக்கும்.
குறியீட்டை இயக்குவதற்கான வெவ்வேறு வழிகள்
1. runInContext
முன்பு உருவாக்கப்பட்ட சூழலில் குறியீட்டை இயக்குகிறது:
const vm = require('vm');
const context = { value: 10 };
vm.createContext(context);
// Run directly
vm.runInContext('value += 5', context);
console.log(context.value); // 15
// Compile then run
const script = new vm.Script('value *= 2');
script.runInContext(context);
console.log(context.value); // 30
2. runInNewContext
ஒரு புதிய சூழலை உருவாக்கி அதில் குறியீட்டை இயக்குகிறது:
const vm = require('vm');
// No need to call createContext first
const context = { value: 10 };
vm.runInNewContext('value += 5; result = value * 2;', context);
console.log(context); // { value: 15, result: 30 }
3. runInThisContext
தற்போதைய V8 சூழலில் குறியீட்டை இயக்குகிறது (eval போன்றது ஆனால் பாதுகாப்பானது):
const vm = require('vm');
// Define a variable in the current scope
const locallet = 20;
let result;
// This won't have access to localVar
vm.runInThisContext('result = (typeof locallet !== "undefined" ? locallet : "not defined")');
console.log(result); // 'not defined'
// But it can access globals
global.globallet = 30;
vm.runInThisContext('result = globalVar');
console.log(result); // 30
// Compare with eval, which CAN access local variables
eval('result = localVar');
console.log(result); // 20
குறிப்பு:
runInThisContext என்பது eval போன்றது, ஆனால் அது அழைக்கப்பட்ட நோக்கத்தில் உள்ளூர் மாறிகள் அணுகல் இல்லை. இது ஓரளவு பாதுகாப்பானதாக்குகிறது, ஏனெனில் இது உள்ளூர் மாறிகளை பாதிக்கும் குறியீடு ஊசி நுழைவு ஆபத்தை குறைக்கிறது.
டைம்அவுட் விருப்பத்துடன் பணிபுரிதல்
முடிவில்லாத சுழற்சிகள் அல்லது நீண்ட-இயக்கும் ஸ்கிரிப்ட்களைத் தடுக்க ஸ்கிரிப்ட் இயக்கத்திற்கு ஒரு டைம்அவுட் அமைக்கலாம்:
const vm = require('vm');
const context = { result: 0 };
vm.createContext(context);
try {
// This should timeout after 1000ms (1 second)
vm.runInContext(`
let counter = 0;
while (true) {
counter++;
result = counter;
}
`, context, { timeout: 1000 });
} catch (err) {
console.error(`Execution timed out: ${err.message}`);
console.log(`Results before timeout: counter reached ${context.result}`);
}
எச்சரிக்கை:
டைம்அவுட் விருப்பம் இயக்கம் குறிப்பிட்ட நேரத்தில் சரியாக நிறுத்தப்படும் என்பதை உறுதிப்படுத்தாது. உண்மையான டைம்அவுட் சற்று மாறுபடலாம்.
Node.js முக்கிய தொகுதிகளுக்கான அணுகலைக் கட்டுப்படுத்துதல்
இயல்புநிலையாக, VM சூழல்களில் இயக்கப்படும் குறியீட்டிற்கு Node.js முக்கிய தொகுதிகள் அணுகல் இல்லை. எந்த தொகுதிகள் கிடைக்கும் என்பதை நீங்கள் கட்டுப்படுத்தலாம்:
const vm = require('vm');
const fs = require('fs');
// Create a sandbox with controlled access to core modules
const sandbox = {
// Allow limited access to console
console: {
log: console.log,
error: console.error
},
// Provide controlled access to fs module
fs: {
readFileSync: fs.readFileSync
},
// Custom utility
util: {
add: (a, b) => a + b,
multiply: (a, b) => a * b
},
// No access to process, child_process, etc.
};
vm.createContext(sandbox);
// Run code with limited access
try {
vm.runInContext(`
// We can use the allowed methods
console.log('Running in sandbox');
console.log('2 + 3 =', util.add(2, 3));
// Try to read a safe file
try {
const content = fs.readFileSync('example.txt', 'utf8');
console.log('File content:', content);
} catch (err) {
console.error('File read error:', err.message);
}
// Try to access process (should fail)
try {
console.log('Process info:', process.version);
} catch (err) {
console.error('Cannot access process:', err.message);
}
`, sandbox);
} catch (err) {
console.error('Sandbox execution failed:', err);
}
எச்சரிக்கை:
நீங்கள் சில தொகுதிகளுக்கான அணுகலைக் கட்டுப்படுத்த முடிந்தாலும், இந்த அணுகுமுறை முற்றிலும் பாதுகாப்பானது அல்ல. ஒரு உறுதியான தாக்குபவர் இன்னும் சாண்ட்பாக்ஸிலிருந்து தப்பிக்க வழிகளைக் கண்டறியக்கூடும். உண்மையான பாதுகாப்பான சாண்ட்பாக்சிங்கிற்கு, கூடுதல் தனிமைப்பாட்டு நுட்பங்கள் அல்லது சிறப்பு நூலகங்களைக் கவனியுங்கள்.
ஒரு எளிய டெம்ப்ளேட் இயந்திரத்தை கட்டமைத்தல்
VM தொகுதி ஒரு எளிய டெம்ப்ளேட் இயந்திரத்தை உருவாக்க பயன்படுத்தப்படலாம்:
const vm = require('vm');
function renderTemplate(template, data) {
// Create template function - replace {{ let }} with values
const templateScript = `
function template(data) {
let output = \`${template.replace(/\{\{\s*(\w+)\s*\}\}/g, '${data.$1}')}\`;
return output;
}
template(data);
`;
// Create a context with the data
const context = { data };
vm.createContext(context);
// Execute the template function
return vm.runInContext(templateScript, context);
}
// Example usage
const template = `
{{ title }}
{{ title }}
Welcome, {{ name }}!
Today is {{ date }}
`;
const data = {
title: 'My Template Page',
name: 'User',
date: new Date().toLocaleDateString()
};
const rendered = renderTemplate(template, data);
console.log(rendered);
குறிப்பு:
இந்த எடுத்துக்காட்டு ஒரு எளிய பயன்பாட்டு வழக்கை நிரூபிக்கிறது, உற்பத்தி டெம்ப்ளேட் இயந்திரங்கள் Handlebars அல்லது EJS போன்றவை மிகவும் உறுதியானவை மற்றும் பாதுகாப்பானவை. பயனர் தரவு சரியாக தப்பிப்பினால் இந்த எடுத்துக்காட்டு ஊசி நுழைவு தாக்குதல்களுக்கு எளிதில் உள்ளாகும்.
ஒரு பிளகின் அமைப்பை உருவாக்குதல்
பிளகின்கள் ஏற்றப்பட்டு தனிமைப்பாட்டில் இயக்கப்படக்கூடிய பிளகின் அமைப்புகளை உருவாக்க VM தொகுதி பயனுள்ளதாக இருக்கிறது:
const vm = require('vm');
const fs = require('fs');
const path = require('path');
class PluginSystem {
constructor() {
this.plugins = new Map();
this.api = {
version: '1.0.0',
registerHook: this.registerHook.bind(this),
utils: {
add: (a, b) => a + b,
multiply: (a, b) => a * b,
formatDate: (date) => new Date(date).toLocaleDateString()
}
};
this.hooks = {
init: [],
process: [],
shutdown: []
};
}
// Register a plugin hook
registerHook(hookName, callback) {
if (this.hooks[hookName]) {
this.hooks[hookName].push(callback);
console.log(`Registered ${hookName} hook`);
} else {
console.error(`Invalid hook name: ${hookName}`);
}
}
// Load a plugin from file
loadPlugin(pluginName, pluginCode) {
try {
console.log(`Loading plugin: ${pluginName}`);
// Create a sandbox for this plugin
const sandbox = {
console: {
log: (msg) => console.log(`[${pluginName}] ${msg}`),
error: (msg) => console.error(`[${pluginName}] ${msg}`)
},
setTimeout,
clearTimeout,
api: this.api
};
// Create context and run the plugin code
const context = vm.createContext(sandbox);
vm.runInContext(pluginCode, context);
// Store the loaded plugin
this.plugins.set(pluginName, {
name: pluginName,
sandbox
});
console.log(`Successfully loaded plugin: ${pluginName}`);
} catch (err) {
console.error(`Error loading plugin ${pluginName}:`, err.message);
}
}
// Run all hooks of a specific type
async runHooks(hookName, data) {
console.log(`Running ${hookName} hooks...`);
for (const hook of this.hooks[hookName]) {
try {
const result = await hook(data);
console.log(`Hook result:`, result);
} catch (err) {
console.error(`Error in ${hookName} hook:`, err.message);
}
}
}
// Load all plugins from a directory
loadPluginsFromDirectory(directory) {
try {
const files = fs.readdirSync(directory);
for (const file of files) {
if (file.endsWith('.js')) {
const pluginName = path.basename(file, '.js');
const pluginPath = path.join(directory, file);
const pluginCode = fs.readFileSync(pluginPath, 'utf8');
this.loadPlugin(pluginName, pluginCode);
}
}
} catch (err) {
console.error('Error loading plugins directory:', err.message);
}
}
// Run the plugin system
async run(data) {
await this.runHooks('init', data);
await this.runHooks('process', data);
await this.runHooks('shutdown', data);
}
}
// Example plugin code (normally this would be in a separate file)
const examplePlugin = `
// Register initialization hook
api.registerHook('init', async (data) => {
console.log('Plugin initializing with data:', data);
return 'Initialization complete';
});
// Register processing hook
api.registerHook('process', async (data) => {
console.log('Processing data');
return {
processed: true,
sum: api.utils.add(data.x, data.y),
product: api.utils.multiply(data.x, data.y),
date: api.utils.formatDate(new Date())
};
});
// Register shutdown hook
api.registerHook('shutdown', async () => {
console.log('Plugin shutting down');
return 'Shutdown complete';
});
console.log('Plugin loaded with API version', api.version);
`;
// Create and run the plugin system
(async () => {
const system = new PluginSystem();
// Load plugins
system.loadPlugin('example', examplePlugin);
// You could also load from a directory
// system.loadPluginsFromDirectory('./plugins');
// Run the system
await system.run({ x: 5, y: 10 });
})();
சிறந்த நடைமுறைகள் மற்றும் பாதுகாப்பு கருத்துகள்
பாதுகாப்பு சிறந்த நடைமுறைகள்
செயல்திறன் சிறந்த நடைமுறைகள்
VM தொகுப்பு vs. eval()
VM தொகுதி eval() ஐப் பயன்படுத்துவதை விட பல நன்மைகளை வழங்குகிறது:
| அம்சம் | VM தொகுப்பு | eval() |
|---|---|---|
| உள்ளூர் மாறிகள் அணுகல் | இல்லை (runInThisContext உடன்) | ஆம் |
| தனிமைப்பாடு | சிறந்தது (தனி சூழல்கள்) | இல்லை (அதே சூழல்) |
| பாதுகாப்பு | சிறந்தது (கட்டுப்படுத்தப்பட்ட சூழல்) | மோசமானது (எல்லாவற்றையும் அணுக முடியும்) |
| மீண்டும் இயக்கத்திற்கான செயல்திறன் | சிறந்தது (முன்கூட்டியே தொகுக்க முடியும்) | மோசமானது (ஒவ்வொரு முறையும் தொகுக்கிறது) |
| இயக்கத்தின் மீதான கட்டுப்பாடு | மேலும் (டைம்அவுட்கள், முதலியன) | குறைவாக |
VM தொகுப்பின் வரம்புகள்
எச்சரிக்கை:
முக்கியமான பாதுகாப்பு பயன்பாடுகளுக்கு, child_process தொகுப்புடன் தனி செயல்முறைகள், கொள்கலன்கள் அல்லது vm2 போன்ற சிறப்பு நூலகங்கள் போன்ற மிகவும் உறுதியான சாண்ட்பாக்சிங் தீர்வுகளைக் கவனியுங்கள்.
சுருக்கம்
Node.js VM தொகுதி தனிமைப்படுத்தப்பட்ட V8 சூழல்களில் JavaScript குறியீட்டை இயக்க ஒரு வழியை வழங்குகிறது. இது பின்வருவனவற்றிற்கு பயனுள்ளதாக இருக்கிறது:
நம்பப்படாத குறியீட்டை இயக்குவதற்கான முழுமையான பாதுகாப்பு தீர்வாக இல்லை என்றாலும், VM தொகுதி eval() ஐ விட அதிக தனிமைப்பாட்டை வழங்குகிறது மற்றும் Node.js பயன்பாடுகளுக்குள் JavaScript மதிப்பீட்டிற்கான ஒரு மதிப்புமிக்க கருவியாகும்.
மேம்பட்ட சூழல் மேலாண்மை
தனிப்பயன் உலகளாவிகள் மற்றும் தொகுதிகளுடன் சிக்கலான VM சூழல்களை உருவாக்குவது மற்றும் நிர்வகிப்பது எப்படி என்பதைக் கற்றுக்கொள்ளுங்கள்:
1. உலகளாவி மாறிகள் கொண்ட தனிப்பயன் சூழலை உருவாக்குதல்
const vm = require('vm');
const util = require('util');
// Create a custom context with specific global variables
const context = {
console: {
log: (...args) => {
// Custom console.log implementation
process.stdout.write('Custom Log: ' + util.format(...args) + '\n');
},
error: console.error,
warn: console.warn,
info: console.info
},
// Add custom utilities
utils: {
formatDate: () => new Date().toISOString(),
generateId: () => Math.random().toString(36).substr(2, 9)
},
// Add a safe require function
require: (moduleName) => {
const allowedModules = ['path', 'url', 'util'];
if (!allowedModules.includes(moduleName)) {
throw new Error(`Module '${moduleName}' is not allowed`);
}
return require(moduleName);
}
};
// Contextify the object
vm.createContext(context);
// Run code in the custom context
const code = `
console.log('Current time:', utils.formatDate());
console.log('Generated ID:', utils.generateId());
try {
const fs = require('fs'); // This will throw an error
} catch (err) {
console.error('Security error:', err.message);
}
// This will work as it's an allowed module
const path = require('path');
console.log('Current directory:', path.dirname('/path/to/file.txt'));
`;
try {
vm.runInContext(code, context, { filename: 'custom-context.js' });
} catch (err) {
console.error('Script execution failed:', err);
}
பாதுகாப்பு சிறந்த நடைமுறைகள்
VM தொகுப்பைப் பயன்படுத்தும் போது, பாதுகாப்பு உங்கள் முதல் முன்னுரிமையாக இருக்க வேண்டும். சில சிறந்த நடைமுறைகள் இங்கே:
const vm = require('vm');
const { execSync } = require('child_process');
// UNSAFE: Directly executing untrusted code
function unsafeEval(code) {
// This is dangerous as it has access to the entire Node.js environment
return vm.runInThisContext(code);
}
// SAFER: Isolated context with limited access
function safeEval(code, timeout = 1000) {
// Create a context with only the necessary globals
const context = {
console: {
log: console.log,
error: console.error
},
// Add safe utilities
Math: Object.create(null),
JSON: {
parse: JSON.parse,
stringify: JSON.stringify
},
// Add a safe setTimeout with limits
setTimeout: (fn, delay) => {
if (delay > 1000) delay = 1000; // Cap delay at 1 second
return setTimeout(fn, delay);
}
};
// Copy safe methods from Math
Object.getOwnPropertyNames(Math)
.filter(prop => typeof Math[prop] === 'function')
.forEach(prop => {
context.Math[prop] = Math[prop];
});
// Create the context without prototype access
const sandbox = vm.createContext(context, {
name: 'sandbox',
codeGeneration: {
strings: false,
wasm: false
}
});
// Run the code with a timeout
try {
const script = new vm.Script(`
(function() {
"use strict";
${code}
})();
`, {
filename: 'sandbox.js',
lineOffset: 0,
displayErrors: true,
timeout: timeout,
microtaskMode: 'afterEvaluate'
});
return script.runInContext(sandbox, { timeout });
} catch (err) {
console.error('Script execution failed:', err.message);
throw new Error('Script execution failed');
}
}
// Example of safe evaluation
try {
const result = safeEval(`
function add(a, b) { return a + b; }
add(2, 3);
`);
console.log('Safe evaluation result:', result); // Outputs: 5
// This will be caught by our safe evaluator
safeEval('process.exit(1)');
} catch (err) {
console.error('Caught error:', err.message);
}
// Example of security risks
console.log('\nTesting security risks:');
try {
console.log('1. Accessing process:');
safeEval('process.versions.node');
} catch (err) {
console.log('✓ Blocked access to process object');
}
try {
console.log('2. Infinite loop:');
safeEval('while(true){}');
} catch (err) {
console.log('✓ Caught infinite loop with timeout');
}
try {
console.log('3. Prototype pollution:');
safeEval('({}).constructor.prototype.polluted = true');
console.log('✓ Blocked prototype pollution');
} catch (err) {
console.log('✓ Blocked prototype pollution');
}
முக்கியமானது:
VM தொகுதி ஒரு பாதுகாப்பு எல்லை அல்ல. உண்மையில் நம்பப்படாத குறியீட்டை இயக்குவதற்கு, Docker, AWS Lambda, அல்லது Google Cloud Functions போன்ற அர்ப்பணிக்கப்பட்ட சாண்ட்பாக்சிங் தீர்வுகளைப் பயன்படுத்துவதைக் கவனியுங்கள்.
செயல்திறன் உகப்பாக்கம்
இந்த நுட்பங்களுடன் VM செயல்திறனை உகப்பாக்குங்கள்:
const vm = require('vm');
const { performance, PerformanceObserver } = require('perf_hooks');
// 1. Compile once, run many times
const expensiveCalculation = new vm.Script(`
function calculate(n) {
let result = 0;
for (let i = 0; i < n; i++) {
result += Math.sqrt(i) * Math.PI;
}
return result;
}
// Return the function reference
calculate;
`);
// Create a context
const context = { Math };
vm.createContext(context);
// Run once to get the function
const calculate = expensiveCalculation.runInContext(context);
// Now we can call the function multiple times without recompiling
console.log('Result (n=1000):', calculate(1000));
console.log('Result (n=2000):', calculate(2000));
// 2. Use code caching for better performance
const cache = new Map();
function compileWithCache(code, filename) {
if (cache.has(code)) {
console.log(`Using cached script for ${filename}`);
return cache.get(code);
}
console.log(`Compiling script for ${filename}`);
const script = new vm.Script(code, {
filename,
cachedData: null, // Will be populated on first run
produceCachedData: true
});
cache.set(code, script);
return script;
}
// 3. Measure performance
function measurePerformance() {
const obs = new PerformanceObserver((items) => {
const entry = items.getEntries()[0];
console.log(`\nExecution time for ${entry.name}: ${entry.duration.toFixed(2)}ms`);
performance.clearMarks();
});
obs.observe({ entryTypes: ['measure'] });
// Test with different script sizes
const smallScript = new vm.Script('let sum = 0; for (let i = 0; i < 1000; i++) sum += i; return sum;');
const largeScript = new vm.Script(`
function processData(data) {
return data.map(x => ({
...x,
processed: true,
timestamp: Date.now(),
hash: require('crypto').createHash('md5').update(JSON.stringify(x)).digest('hex')
}));
}
// Process sample data
const data = Array(1000).fill(null).map((_, i) => ({ id: i, value: Math.random() }));
return processData(data);
`);
// Measure execution
performance.mark('small-start');
smallScript.runInThisContext();
performance.mark('small-end');
performance.mark('large-start');
largeScript.runInThisContext();
performance.mark('large-end');
performance.measure('Small script execution', 'small-start', 'small-end');
performance.measure('Large script execution', 'large-start', 'large-end');
}
// Run performance test
measurePerformance();
// 4. Reuse contexts for better performance
function createOptimizedContext() {
const context = {
// Only include what's necessary
console: {
log: console.log,
error: console.error
},
// Add required globals
setTimeout,
clearTimeout,
// Add custom utilities
utils: {
formatNumber: n => new Intl.NumberFormat().format(n),
formatDate: d => d.toISOString()
}
};
// Create context once
vm.createContext(context);
return context;
}
// Reuse the same context for multiple scripts
const sharedContext = createOptimizedContext();
// Run multiple scripts with the same context
function runWithSharedContext(code) {
try {
const script = new vm.Script(code);
return script.runInContext(sharedContext);
} catch (err) {
console.error('Script execution failed:', err);
throw err;
}
}
// Example usage
const script1 = 'console.log("Script 1:", utils.formatNumber(1234567.89));';
const script2 = 'console.log("Script 2:", utils.formatDate(new Date()));';
runWithSharedContext(script1);
runWithSharedContext(script2);